package com.crane.framework.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.crane.framework.constant.SystemConst;
import com.crane.framework.dto.*;
import com.crane.framework.entity.Role;
import com.crane.framework.entity.User;
import com.crane.framework.entity.UserRole;
import com.crane.framework.exception.RRException;
import com.crane.framework.mapper.UserMapper;
import com.crane.framework.service.*;
import com.crane.framework.utils.CommonUtil;
import com.crane.framework.utils.SmUtil;
import com.crane.framework.utils.SystemUtil;
import com.crane.framework.vo.UserListVO;
import com.crane.framework.vo.WxLoginVO;
import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author 47349
 * @description 针对表【sys_user(用户表)】的数据库操作Service实现
 * @createDate 2024-01-16 23:53:06
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

  @Resource private IUserRoleService userRoleService;
  @Resource private IFileService fileService;
  @Resource private IDictService dictService;
  @Resource private IRoleService roleService;

  @Override
  public SaTokenInfo login(User user) {
    String userId = user.getId();
    List<Role> roleList = userRoleService.getRoleListByUserId(userId);

    return login(userId, roleList);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public SaTokenInfo login_wx(WxLoginVO wxLoginVO, WxLoginDTO wxLoginDTO) {
    User user = this.lambdaQuery().eq(User::getWxOpenId, wxLoginVO.getOpenid()).one();
    Role role = roleService.lambdaQuery().eq(Role::getRoleSign, SystemConst.wxRoleSign).one();
    if (CommonUtil.isNullOrEmpty(user)) {
      user = new User();
      user.setNickname(wxLoginDTO.getNickname());
      user.setWxAvatar(wxLoginDTO.getAvatar());
      user.setWxOpenId(wxLoginVO.getOpenid());
      user.setUsername(wxLoginVO.getOpenid());
      user.setPassword(SmUtil.sm3(SystemConst.DefaultPassword));
      this.save(user);

      UserRole userRole = new UserRole();
      userRole.setUserId(user.getId());

      userRole.setRoleId(role.getId());
      userRoleService.save(userRole);
    }

    return login(user.getId(), Collections.singletonList(role));
  }

  @Override
  public List<UserAuthDTO> getUserAuthList() {
    List<User> userList = this.list();
    if (CommonUtil.isNullOrEmpty(userList)) {
      return null;
    }

    List<String> userIdList = userList.stream().map(User::getId).toList();

    Map<String, List<String>> roleMapByUserId = userRoleService.getRoleSignMapByUserId(userIdList);

    if (CommonUtil.isNullOrEmpty(roleMapByUserId)) {
      return null;
    }

    List<UserAuthDTO> userAuthDTOList = new ArrayList<>();

    for (User user : userList) {
      UserAuthDTO userAuthDTO = new UserAuthDTO();
      userAuthDTO.setUsername(user.getUsername());
      userAuthDTO.setPassword(user.getPassword());
      userAuthDTO.setRole(roleMapByUserId.get(user.getId()));
      userAuthDTOList.add(userAuthDTO);
    }

    return userAuthDTOList;
  }

  @Override
  public Page<UserListVO> getUserList(UserPageDTO userPageDTO) {
    String email = userPageDTO.getEmail();
    String username = userPageDTO.getUsername();
    String sex = userPageDTO.getSex();
    String nickname = userPageDTO.getNickname();
    String realName = userPageDTO.getRealName();
    String idCard = userPageDTO.getIdCard();
    String phone = userPageDTO.getPhone();
    List<String> userIds = userPageDTO.getUserIds();

    Page<User> page = SystemUtil.buildPageFromDTO(userPageDTO, User.class);
    page =
        this.lambdaQuery()
            .in(CommonUtil.notNullOrEmpty(userIds), User::getId, userIds)
            .like(CommonUtil.notNullOrEmpty(email), User::getEmail, email)
            .like(CommonUtil.notNullOrEmpty(username), User::getUsername, username)
            .eq(CommonUtil.notNullOrEmpty(sex), User::getSex, sex)
            .like(CommonUtil.notNullOrEmpty(nickname), User::getNickname, nickname)
            .like(CommonUtil.notNullOrEmpty(realName), User::getRealName, realName)
            .like(CommonUtil.notNullOrEmpty(idCard), User::getIdCard, idCard)
            .like(CommonUtil.notNullOrEmpty(phone), User::getPhone, phone)
            .orderByDesc(User::getGmtCreate)
            .page(page);

    Page<UserListVO> buildResource = SystemUtil.buildResource(page, UserListVO.class);
    fileService.transfer(buildResource);
    dictService.transfer(buildResource);

    Map<String, List<String>> roleMapByUserId = new HashMap<>();

    if (CommonUtil.notNullOrEmpty(buildResource.getRecords())) {
      List<String> userIdList = buildResource.getRecords().stream().map(UserListVO::getId).toList();

      roleMapByUserId = userRoleService.getRoleNameMapByUserId(userIdList);
    }

    Map<String, List<String>> finalRoleMapByUserId = roleMapByUserId;
    buildResource
        .getRecords()
        .forEach(user -> user.setRoleNameList(finalRoleMapByUserId.get(user.getId())));

    return buildResource;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void addUser(UserAddDTO userAddDTO) {
    String username = userAddDTO.getUsername();
    String phone = userAddDTO.getPhone();
    String email = userAddDTO.getEmail();

    checkUser(username, phone, email);

    User user = SystemUtil.buildResource(userAddDTO, User.class);
    String password = SmUtil.sm3(SystemConst.DefaultPassword);
    user.setPassword(password);
    this.save(user);
    List<String> roleIdList = userAddDTO.getRoleIdList();

    setRole(user.getId(), roleIdList);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void removeUser(String userId) {
    List<Role> roleList = userRoleService.getRoleListByUserId(userId);
    if (CommonUtil.isNullOrEmpty(roleList)) {
      this.removeById(userId);
    }
    List<String> roleSignList = roleList.stream().map(Role::getRoleSign).toList();

    if (CollUtil.containsAny(roleSignList, SystemConst.CanNotDelRole)) {
      throw new RRException("不能删除该用户");
    }

    userRoleService.removeByUserId(userId);
    this.removeById(userId);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void updateUser(UserUpdateDTO userUpdateDTO) {
    User queryUser = this.getById(userUpdateDTO.getId());
    String username = userUpdateDTO.getUsername();
    String phone = userUpdateDTO.getPhone();
    String email = userUpdateDTO.getEmail();

    if (CommonUtil.notNullOrEmpty(username) && !queryUser.getUsername().equals(username)) {
      checkUser(username, null, null);
    }
    if (CommonUtil.notNullOrEmpty(phone) && !queryUser.getPhone().equals(phone)) {
      checkUser(null, phone, null);
    }
    if (CommonUtil.notNullOrEmpty(email) && !queryUser.getEmail().equals(email)) {
      checkUser(null, null, email);
    }

    User user = SystemUtil.buildResource(userUpdateDTO, User.class);
    this.updateById(user);

    userRoleService.removeByUserId(user.getId());

    setRole(user.getId(), userUpdateDTO.getRoleIdList());
  }

  /**
   * 检查用户
   *
   * @param username
   * @param phone
   * @param email
   */
  private void checkUser(String username, String phone, String email) {
    Long userCheck =
        this.lambdaQuery()
            .eq(CommonUtil.notNullOrEmpty(username), User::getUsername, username)
            .or()
            .eq(CommonUtil.notNullOrEmpty(phone), User::getPhone, phone)
            .or()
            .eq(CommonUtil.notNullOrEmpty(email), User::getEmail, email)
            .count();

    if (userCheck > 0) {
      throw new RRException("用户名或手机号已存在");
    }
  }

  /**
   * 设置角色
   *
   * @param id
   * @param roleIdList
   */
  private void setRole(String id, List<String> roleIdList) {
    List<UserRole> userRoleList = new ArrayList<>();
    roleIdList.forEach(
        roleId -> {
          UserRole userRole = new UserRole();
          userRole.setUserId(id);
          userRole.setRoleId(roleId);
          userRoleList.add(userRole);
        });
    userRoleService.saveBatch(userRoleList);
  }

  private SaTokenInfo login(Object id, List<Role> roleList) {
    // 登录获取token信息
    StpUtil.login(id);
    SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

    // 获取角色信息
    List<String> roleStringList = new ArrayList<>();
    if (CommonUtil.notNullOrEmpty(roleList)) {
      roleStringList = roleList.stream().map(Role::getRoleSign).collect(Collectors.toList());
    }

    // 注入sa-token
    StpUtil.getSession().set("roleList", roleStringList);

    return tokenInfo;
  }
}
